from __future__ import absolute_import
import json
import logging
import traceback
import re
import datetime
import uuid
from collections import namedtuple
import random
import requests
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.utils import timezone
from django.db.models import F, Q
from django.middleware.csrf import get_token
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from obs import RestoreTier, SetObjectMetadataHeader
from monitor.models import MonitorRealTimeInfo, MonitorAlarm
from data_mgt.models import AsyncJobSceneCut, AnonymizedData, \
    DataDownloadInfo, ObsAsyncJobStatus
from data_mgt.serializer import AnonymizedDataSerializer
from conf.conf import data_mgt_apis
from common.tools import record_ip, auth_request, fill_filter_data, set_header
from common.obs_tools import obs_client, object_restore_status, get_job_type
from common.ploto_enum import CommonStatuEnum, DataStatuEnum
from common.ploto_response import PlotoResponse

logger = logging.getLogger(__name__)


class AnonymizedDataHandler(APIView):
    """
    单个脱敏数据对象的操作类
    """

    @record_ip
    @auth_request
    def get(self, request, pk):
        """
        获取单条脱敏数据的详情
        param request,pk
        return: data + list_tag
        1、获取pk对应的数据obj
        2、并获取对应的tag字段信息，返回list_tag，方便前端更新此字段
        """
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.view_anonymizeddata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            response.status = status.HTTP_403_FORBIDDEN
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        obj = AnonymizedData.objects.get(id=pk)
        list_tag = obj.tag.split('|')
        try:
            serializer = AnonymizedDataSerializer(obj)
            response.data = serializer.data
            response.data["list_tag"] = list_tag
            return Response(response.dict, status=status.HTTP_200_OK)
        except Exception as e:
            logger.error("序列化异常:%s, %s", repr(e), traceback.format_exc())
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            response.status = status.HTTP_500_INTERNAL_SERVER_ERROR
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    @record_ip
    def post(self, request):
        """
        脱敏数据新增接口
        :param request:
        :return: data  新增数据信息
        1、获取request写入的数据信息
        2、保存数据信息，并返回
        """
        response = PlotoResponse()
        params = request.data
        if isinstance(params, dict):
            params = [params]
        data_list = []
        data_to_next = []
        for data in params:
            uuid_gen = str(uuid.uuid4())
            data_list.append(AnonymizedData(name=data.get('name', ''),
                                            size=data.get('size', 0),
                                            car_id=data.get('car_id', ''),
                                            data_type=data.get('data_type', 0),
                                            region=data.get('region', ''),
                                            url=data.get('url', ''),
                                            is_delete=data.get('is_delete', False),
                                            source_type=data.get('source_type', 0),
                                            tag=data.get('tag', ''),
                                            remark=data.get('remark', ''),
                                            collect_time=data.get('collect_time', ''),
                                            storage_type=data.get('storage_type', 0),
                                            source_id=data.get('source_id', 0),
                                            uuid=uuid_gen))
            data_to_next.append({"url": data.get("url"), "name": data.get("name", ""), "uuid": uuid_gen})
        try:
            AnonymizedData.objects.bulk_create(data_list)
            response.data["info"] = "Add scene success"
        except Exception as e:
            logger.error("数据库更新失败:%s, %s", repr(e), traceback.format_exc())
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            response.data["Error: "] = repr(e)
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        # 默认自动流转，如果要手动流转，request请求带”auto_scene_cut“ 为 0
        if "auto_scene_cut" not in request.data or request.data.get("auto_scene_cut") == 1:
            resp_scene_cut = requests.post(url="http://localhost:8000/data/anonymized/scenecut",
                                           data=json.dumps(data_to_next), headers=request.headers)
            if resp_scene_cut.status_code > 300:
                response.code = CommonStatuEnum.INTERNAL_ERROR.code
                response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
                response.data["error: "] = "scene cut failed"
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        response.code = CommonStatuEnum.OK.code
        response.msg = CommonStatuEnum.OK.msg
        return Response(response.dict, status=status.HTTP_200_OK)

    def put(self, request, pk):
        """
        单条脱敏数据修改
        :param request
        :param pk
        :return: data  新增数据信息
        1、获取指定id的obj信息
        2、获取修改的操作  针对取回/归档/修改tag/修改其他字段
        2.1 前端传了tag字段，则表示更新了tag
           a、用. join()连接前端传的数据
           b、并更新到对应的数据字段
           c、并将更新的数据返回给前端更新
        2.2 修改其他字段：通过序列化的方式更新修改的字段
        2.3 取回和归档的逻辑参考_retrieval和_save_cold流程
        """
        params = request.data
        # 修改 tag字段
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.change_anonymizeddata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        tag = params.get('tag', '')
        remark = params.get('remark', '')
        # 修改标签字段
        if tag:
            tag_str = "|".join(tag)
            resp = AnonymizedData.objects.filter(id=pk).update(tag=tag_str)
            if resp != 1:
                logger.error("数据库更新失败")
                response.code = CommonStatuEnum.INTERNAL_ERROR.code
                response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        # 修改描述字段
        if remark:
            resp = AnonymizedData.objects.filter(id=pk).update(remark=remark)
            if resp != 1:
                logger.error("数据库更新失败")
                response.code = CommonStatuEnum.INTERNAL_ERROR.code
                response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        return Response(response.dict, status=status.HTTP_201_CREATED)

    def delete(self, request, pk):
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.delete_anonymizeddata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        resp = AnonymizedData.objects.filter(id=pk).update(is_delete=True)
        if resp != 1:
            logger.error("场景数据表更新失败")
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        delete_status = do_delete(pk)
        if delete_status is False:
            logger.error("obs数据删除失败")
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        return Response(response.dict, status=status.HTTP_204_NO_CONTENT)


class BatchAnonymizedData(APIView):

    @auth_request
    def get(self, request):
        """
        批量脱敏数据获取
        :param request
        :return: data
        1、获取分页标记信息
        2、指定部分字段为模糊匹配搜索以及按区间搜索的字段
        3、获取根据过滤条件得到的数据信息
        4、序列化分页数据，返回给数据信息给前端
        """
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.view_anonymizeddata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        params = request.query_params.dict()
        # 获取分页标记信息,默认为1,page_size 默认为10
        page = int(params.get('page', 1))
        page_size = int(params.get('page_size', 10))
        filter_data = fill_filter_data(params)
        anonymize_data_list = AnonymizedData.objects.filter(**filter_data)
        #  没有数据提示 传空数据出去
        if anonymize_data_list.count() == 0:
            return Response(response.dict, status=status.HTTP_200_OK)
        paginator = Paginator(anonymize_data_list, page_size)
        try:
            page_anonymize_data_list = paginator.page(page)
        except PageNotAnInteger:
            page_anonymize_data_list = paginator.page(1)
        except EmptyPage:
            page_anonymize_data_list = paginator.page(paginator.num_pages)
        try:
            anonymize_data = AnonymizedDataSerializer(instance=page_anonymize_data_list, many=True)
            response.data["data_list"] = anonymize_data.data
            response.data["count"] = paginator.count
            return Response(response.dict, status=status.HTTP_200_OK)
        except Exception as e:
            logger.error("序列化异常:%s, %s", repr(e), traceback.format_exc())
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def delete(self, request):
        """
        批量脱敏数据删除
        :param request
        :return: data
        1、获取前端传入的ids信息
        2、根据ids调用数据库的filter 和 update操作
        """
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.delete_anonymizeddata'):
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        id_list = request.POST.get('ids')
        if not id_list:
            response.msg = CommonStatuEnum.VALID_EXCEPTION.msg
            response.code = CommonStatuEnum.VALID_EXCEPTION.code
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)
        delete_id_list = id_list.split(',')
        try:
            AnonymizedData.objects.filter(id__in=delete_id_list).update(is_delete=True)
            for delete_id in delete_id_list:
                delete_status = do_delete(delete_id)
                if delete_status is False:
                    logger.error("obs数据删除失败")
                    response.code = CommonStatuEnum.INTERNAL_ERROR.code
                    response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
                    return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            return Response(response.dict, status=status.HTTP_204_NO_CONTENT)
        except Exception as e:
            logger.error("数据库更新失败:%s, %s", repr(e), traceback.format_exc())
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class AnonymizedDataFileHandler(APIView):

    @auth_request
    def get(self, request, pk):
        """
        脱敏数据修文件下载
        :param request
        :param pk
        :return: signedUrl
        1、根据id 信息获取数据库中对心的信息 并解析桶名和对象名
        2、如果是归档存储  恢复状态未恢复中或者未恢复 是不提供下载功能的
        3、设置header的contentType信息 为直接下载不播放 调用obs的接口 在元数据中设置
        4、 调用obs接口  获取授权的url信息
        5、同步下载信息到下载信息表中
        6、同步表中的下载次数
        """
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.download_anonymizeddata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        obj = AnonymizedData.objects.filter(id=pk)
        if None is re.match(r'^obs://\S+/.+[^/]+$', obj[0].url):
            logger.warning("脱敏数据url无效")
            response.code = DataStatuEnum.ANONYMIZE_URL_EXCEPTION.code
            response.msg = DataStatuEnum.ANONYMIZE_URL_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)
        bucket_name = obj[0].url.split("/")[2]
        object_key = obj[0].url.split("/", 3)[-1]
        # 当前规避：归档存储   恢复中和未恢复  不能下载
        if obj[0].storage_type == 2:
            restore_status = object_restore_status(bucket_name, object_key)
            if restore_status in {'no_restored', 'restoring'}:
                alarm_details = str(self.request.user) + "用户下载脱敏后数据文件" + object_key + "失败"
                MonitorAlarm.objects.create(alarm_time=timezone.now(), alarm_content='下载异常',
                                            alarm_details=alarm_details, level=0)
                response.code = DataStatuEnum.DOWNLOAD_EXCEPTION.code
                response.msg = DataStatuEnum.DOWNLOAD_EXCEPTION.msg
                return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)
        headers = SetObjectMetadataHeader()
        headers.contentType = "application/octet-stream"
        # mp4文件默认为播放，需要添加contentType就可以直接下载不播放
        res = obs_client.setObjectMetadata(bucket_name, object_key, headers=headers)
        if res.status >= 300:
            logger.error("设置对象元数据失败:%s, %s", res.errorCode, res.errorMessage)
            response.code = DataStatuEnum.SET_METADATA_EXCEPTION.code
            response.msg = DataStatuEnum.SET_METADATA_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)
        try:
            resp = obs_client.createSignedUrl('GET', bucket_name, object_key, expires=3600)
        except Exception as e:
            alarm_details = str(self.request.user) + "用户下载脱敏后数据文件" + object_key + "失败"
            try:
                MonitorAlarm.objects.create(alarm_time=timezone.now(), alarm_content='下载异常',
                                            alarm_details=alarm_details, level=0)
            except Exception as exception:
                logger.error("告警数据表插入数据失败: %s, %s", repr(exception), traceback.format_exc())
            logger.error("创建下载url:%s, %s", repr(e), traceback.format_exc())
            response.code = DataStatuEnum.GET_DOWNLOAD_URL_EXCEPTION.code
            response.msg = DataStatuEnum.GET_DOWNLOAD_URL_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        # 同步下载数据到数据下载信息表中
        try:
            DataDownloadInfo.objects.create(data_id=pk, data_type=1, data_version=obj[0].version,
                                            user=self.request.user)
            info_content = str(self.request.user) + "用户下载脱敏后数据文件" + object_key
            MonitorRealTimeInfo.objects.create(create_time=timezone.now(), info_content=info_content)
            # 同步下载次数字段值
            AnonymizedData.objects.filter(id=pk).update(download_times=F('download_times') + 1)
            response.data["data"] = resp.signedUrl
            return Response(response.dict, status=status.HTTP_200_OK)
        except Exception as e:
            logger.error("数据下载信息表同步失败:%s, %s", repr(e), traceback.format_exc())
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class AnonymizedDataRestore(APIView):
    AnonymizeParam = \
        namedtuple('AnonymizeParam', ['days_num', 'fail_dict', 'obj_list', 'success_object', 'tier'])

    def post(self, request):
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.restore_anonymizeddata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        params = request.data
        days_num = params.get("days_num", 30)
        rate = params.get("rate", 'STANDARD')
        id_list = params.get('ids', [])
        success_object = []
        fail_dict = {}
        tier = RestoreTier.EXPEDITED if rate == 'EXPEDITED' else RestoreTier.STANDARD
        obj_list = AnonymizedData.objects.filter(id__in=id_list)
        if obj_list is None:
            response.code = DataStatuEnum.NOT_EXIST_EXCEPTION.code
            response.msg = DataStatuEnum.NOT_EXIST_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_404_NOT_FOUND)
        anonymize_param = self.AnonymizeParam(days_num=days_num, fail_dict=fail_dict,
                                              obj_list=obj_list, success_object=success_object, tier=tier)
        self._do_restore(anonymize_param)
        if success_object:
            if fail_dict:
                response.code = DataStatuEnum.RESTORE_EXCEPTIOM.code
                response.msg = DataStatuEnum.RESTORE_EXCEPTIOM.msg
                response.data = fail_dict
                return Response(response.dict, status=status.HTTP_206_PARTIAL_CONTENT)
            else:
                return Response(response.dict, status=status.HTTP_200_OK)
        else:
            response.code = DataStatuEnum.RESTORE_EXCEPTIOM.code
            response.msg = DataStatuEnum.RESTORE_EXCEPTIOM.msg
            response.data = fail_dict
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)

    def _do_restore(self, anonymize_param):
        days_num, fail_dict, obj_list, success_object, tier = anonymize_param
        for obj in obj_list:
            if None is re.match(r'^obs://\S+/.+[^/]+$', obj.url):
                fail_dict[obj.name] = DataStatuEnum.ANONYMIZE_URL_EXCEPTION.msg
                logger.warning("脱敏数据%s url无效", obj.name)
                continue
            bucket_name = obj.url.split("/")[2]
            object_key = obj.url.split("/", 3)[-1]
            restore_status = object_restore_status(bucket_name, object_key)
            if restore_status in {'no_restored', 'restored'}:
                resp = obs_client.restoreObject(bucket_name, object_key, days_num, tier)
                if resp.status < 300:
                    try:
                        ObsAsyncJobStatus.objects.create(job_id=obj.id, job_data_type=0, job_type=get_job_type(tier),
                                                         job_bucket=bucket_name, job_object=object_key,
                                                         next_run_time=timezone.now())
                    except Exception as e:
                        logger.error("异步任务表新增数据失败:%s, %s", repr(e), traceback.format_exc())
                        fail_dict[obj.name] = CommonStatuEnum.INTERNAL_ERROR.msg
                    try:
                        # 对于取回的成功的对象 需要修改其恢复状态  当前设置为恢复中 规避方法下一次操作的时候先查（恢复中->已恢复）
                        AnonymizedData.objects.filter(id=obj.id).update(restoration_status=2)
                    except Exception as e:
                        logger.error("脱敏数据表更新失败:%s, %s", repr(e), traceback.format_exc())
                        fail_dict[obj.name] = CommonStatuEnum.INTERNAL_ERROR.msg
                    success_object.append(obj.name)
                else:
                    fail_dict[obj.name] = resp.errorMessage
            else:
                fail_dict[obj.name] = DataStatuEnum.RESTORING_NOT_ALLOWED.msg


class AnonymizedDataModifyStorageClass(APIView):
    AnonymizeParam = \
        namedtuple('AnonymizeParam', ['fail_dict', 'headers', 'obj', 'resp', 'storage_class', 'success_object'])
    ModifyParam = namedtuple('ModifyParam', ['fail_dict', 'headers', 'obj_list', 'success_object', 'storage_class'])

    def post(self, request):
        response = PlotoResponse()
        if not request.user.has_perm('data_mgt.modify_class_anonymizeddata'):
            response.code = CommonStatuEnum.AUTHORIZATION_EXCEPTION.code
            response.msg = CommonStatuEnum.AUTHORIZATION_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_403_FORBIDDEN)
        params = request.data
        id_list = params.get('ids', [])
        storage_class = params.get("storage_class")
        headers = SetObjectMetadataHeader()
        set_header(headers, storage_class)
        success_object = []
        fail_dict = {}
        obj_list = AnonymizedData.objects.filter(id__in=id_list)
        if obj_list is None:
            response.code = DataStatuEnum.NOT_EXIST_EXCEPTION.code
            response.msg = DataStatuEnum.NOT_EXIST_EXCEPTION.msg
            return Response(response.dict, status=status.HTTP_404_NOT_FOUND)
        modify_param = self.ModifyParam(fail_dict=fail_dict, headers=headers, obj_list=obj_list,
                                        success_object=success_object, storage_class=storage_class)
        self._get_modify_result(modify_param)
        # 结果返回
        if success_object:
            if fail_dict:
                response.msg = DataStatuEnum.MODIFY_CLASS_EXCEPTION.msg
                response.code = DataStatuEnum.MODIFY_CLASS_EXCEPTION.code
                response.data = fail_dict
                return Response(response.dict, status=status.HTTP_206_PARTIAL_CONTENT)
            else:
                return Response(response.dict, status=status.HTTP_200_OK)
        else:
            response.msg = DataStatuEnum.MODIFY_CLASS_EXCEPTION.msg
            response.code = DataStatuEnum.MODIFY_CLASS_EXCEPTION.code
            response.data = fail_dict
            return Response(response.dict, status=status.HTTP_400_BAD_REQUEST)

    def _get_modify_result(self, modify_param):
        fail_dict, headers, obj_list, success_object, storage_class = modify_param
        for obj in obj_list:
            source_storage_class = obj.storage_type
            url = obj.url
            if None is re.match(r'^obs://\S+/.+[^/]+$', url):
                fail_dict[obj.name] = DataStatuEnum.ANONYMIZE_URL_EXCEPTION.msg
                logger.warning("脱敏数据%s url无效", obj.name)
                continue
            bucket_name = url.split("/")[2]
            object_key = url.split("/", 3)[-1]
            if source_storage_class == 2:
                restore_status = object_restore_status(bucket_name, object_key)
                if restore_status == 'restored':
                    resp = obs_client.setObjectMetadata(bucket_name, object_key, headers=headers)
                    anonymize_param = self.AnonymizeParam(fail_dict=fail_dict, headers=headers, obj=obj, resp=resp,
                                                          storage_class=storage_class, success_object=success_object)
                    self._do_response(anonymize_param)
                else:
                    fail_dict[obj.name] = DataStatuEnum.MODIFY_CLASS_NOT_ALLOWED.msg
            else:
                resp = obs_client.setObjectMetadata(bucket_name, object_key, headers=headers)
                anonymize_param = self.AnonymizeParam(fail_dict=fail_dict, headers=headers, obj=obj, resp=resp,
                                                      storage_class=storage_class, success_object=success_object)
                self._do_response(anonymize_param)

    def _do_response(self, anonymize_param):
        fail_dict, headers, obj, resp, storage_class, success_object = anonymize_param
        if resp.status < 300:
            try:
                # 执行成功的id  更新对应的字段  修改为归档存储时 恢复状态为未恢复  修改为其他存储类别 则恢复状态为--
                if headers.storageClass == 'COLD':
                    AnonymizedData.objects.filter(id=obj.id).update(storage_type=storage_class,
                                                                    restoration_status=1)
                else:
                    AnonymizedData.objects.filter(id=obj.id).update(storage_type=storage_class,
                                                                    restoration_status=0)
            except Exception as e:
                logger.error("脱敏数据表更新失败:%s, %s", repr(e), traceback.format_exc())
                fail_dict[obj.name] = CommonStatuEnum.INTERNAL_ERROR.msg
            success_object.append(obj.name)
        else:
            logger.error("obs调用失败%s, %s", resp.errorCode, resp.errorMessage)
            fail_dict[obj.name] = resp.errorMessage


class AnonymizedDataCirculate(APIView):
    """
    脱敏数据流转接口：
    1、获取参数信息
    2、根据脱敏数据信息调用第三方接口获得bag_id
    3、根据bag_id调用第三方接口获取场景提取task_id
    4、将task_id等信息存入异步任务表
    """
    def post(self, request):
        response = PlotoResponse()
        params = request.data
        if isinstance(params, dict):
            params = [params]
        data_list = []
        success_list = []
        session_id = request.headers.get("sessionid", "")
        user_name = request.user
        default_scenes_list = ["follow_big_car", "cut_in-1", "cut_in-2", "overtake", "confluence", "follow_and_stop"]
        for data in params:
            # 要提取的场景list，如果没设置就默认全部
            if "scene_list" in data:
                scenes_list = data.get("scene_list", "")
            else:
                scenes_list = default_scenes_list
            anonymized_data_path = data.get("url")
            bucket_name = anonymized_data_path.split("/")[2]
            file_name = anonymized_data_path.split("/")[-1]
            try:
                anonymized_id = AnonymizedData.objects.filter(uuid=data.get('uuid', ''))[0]
            except Exception as e:
                logger.error("原始数据查询出错:%s, %s", repr(e), traceback.format_exc())
                response.code = CommonStatuEnum.VALID_EXCEPTION.code
                response.msg = CommonStatuEnum.VALID_EXCEPTION.msg
                response.data["errno"] = response_add_bag_json.get('errno')
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            add_bag_response = self._do_add_bag(data)
            response_add_bag_json = json.loads(add_bag_response)
            if response_add_bag_json.get('errno') > 0:
                logger.error("场景数据包添加失败:%s", response_add_bag_json['errmsg'])
                response.code = CommonStatuEnum.VALID_EXCEPTION.code
                response.msg = CommonStatuEnum.VALID_EXCEPTION.msg
                response.data["errno"] = response_add_bag_json.get('errno')
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            scene_cut_response = self._do_scene_cut(response_add_bag_json, bucket_name, file_name, scenes_list)
            rep_json = json.loads(scene_cut_response)
            if rep_json.get('errno') > 0:
                logger.error("添加场景提取任务失败%s", rep_json['errmsg'])
                response.code = CommonStatuEnum.VALID_EXCEPTION.code
                response.msg = CommonStatuEnum.VALID_EXCEPTION.msg
                response.data["errno"] = response_add_bag_json.get('errno')
                return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

            if rep_json.get("status_code") == 200 and rep_json.get("errno") == 0:
                logger.info("isv bags cut scene success.")
                scene_cut_task_id = rep_json.get("data").get("task_id") + str(random.randint(1, 1000))
            else:
                error_msg = rep_json.get("errmsg")
                logger.error(error_msg)
            bag_id = response_add_bag_json.get("data", {}).get("bag_id", None)
            token = get_token(request)
            data_list.append(AsyncJobSceneCut(task_id=scene_cut_task_id,
                                              sessionid=session_id,
                                              username=user_name,
                                              data_id=bag_id,
                                              anonymized_id=anonymized_id,
                                              token=token))
            success_list.append(scene_cut_task_id)
        try:
            AsyncJobSceneCut.objects.bulk_create(data_list)
            response.data["task_id"] = success_list
            return Response(response.dict, status=status.HTTP_200_OK)
        except Exception as e:
            logger.error("场景提取异步任务插入失败:%s, %s", repr(e), traceback.format_exc())
            response.code = CommonStatuEnum.INTERNAL_ERROR.code
            response.msg = CommonStatuEnum.INTERNAL_ERROR.msg
            return Response(response.dict, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def _do_add_bag(self, data):
        anonymized_data_path = data.get("url")
        file_name = anonymized_data_path.split("/")[-1]
        date_str = datetime.datetime.today().strftime("%Y%m%d%H%M%S")
        bag_remark = "add from obs event.create time is {}".format(date_str)
        post_body = {"name": file_name, "path": anonymized_data_path, "remarks": bag_remark}
        headers = {"Content-Type": "application/json"}
        api_bags_add_isv = data_mgt_apis.get("bags_add", None)
        # 模拟第三方接口使用 add_bag_response = add_bag_response_test()
        add_bag_response = requests.post(url=api_bags_add_isv, data=json.dumps(post_body), headers=headers)
        return add_bag_response

    def _do_scene_cut(self, response_add_bag_json, bucket_name, file_name, scenes_list):
        headers = {"Content-Type": "application/json"}
        bag_id = response_add_bag_json.get("data", {}).get("bag_id", None)
        bag_path = response_add_bag_json.get("data", {}).get("url", None)
        api_bags_scene_cut = data_mgt_apis.get("scene_cut", None)
        date_str = datetime.datetime.today().strftime("%Y%m%d%H%M%S")
        obs_output_dir = "obs://{}/scene/{}/{}".format(bucket_name, file_name, date_str)
        data = {"bag_id": bag_id, "bag_path": bag_path, "obs_output_dir": obs_output_dir, "scenes": scenes_list}
        # 模拟第三方接口使用 scene_cut_response = scene_cut_response_test()
        scene_cut_response = requests.post(url=api_bags_scene_cut, data=json.dumps(data), headers=headers)
        return scene_cut_response


def do_delete(pk):
    obj = AnonymizedData.objects.get(id=pk)
    object_url = obj.url
    bucket_name = object_url.split("/")[2]
    object_key_path = object_url.split("/", 3)[-1]
    resp = obs_client.listObjects(bucket_name, prefix=object_key_path)
    for content in resp.body.contents:
        delete_url = content.key
        delete_resp = obs_client.deleteObject(bucket_name, delete_url)
        if delete_resp.status >= 300:
            return False
    return True


def add_bag_response_test():
    text = json.dumps(
        {
            "status_code": 200,
            "errno": 0,
            "errmsg": "OK",
            "task_id": "123",
            "data": {
                "id": "123",
                "status": 6,
                "create_at": 1650624326149,
                "update_at": 1650628238192,
                "task_id": "123",
                "url": "obs://ploto-test/_2021-06-04-14-53-55.bag",
                "bag_id": "12312"
            },
            "details": None
        })
    return text


def scene_cut_response_test():
    text = json.dumps(
        {
            "status_code": 200,
            "errno": 0,
            "errmsg": "OK",
            "data": {
                "id": "123",
                "status": 6,
                "create_at": 1650624326149,
                "update_at": 1650628238192,
                "task_id": "123",
                "url": "obs://ploto-test/holo/test_data_2021-06-04-14-53-55.__perception_04-1__321",
                "bag_id": "12312"
            },
            "details": None
        })
    return text
